package org.wisdom.ac.apis.controller;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.data.domain.*;
import org.wisdom.ac.apis.ResourceController;
import org.wisdom.ac.apis.assembler.ResourceAssembler;
import org.wisdom.ac.domain.resource.entity.*;
import org.wisdom.ac.domain.resource.repository.*;
import org.wisdom.ac.dto.ResourceDto;
import org.wisdom.ac.dto.ResourcesDto;
import org.wisdom.annotation.EnableDataFilter;
import org.wisdom.annotation.WisdomController;
import org.wisdom.context.WisdomContextHolder;
import org.wisdom.dto.BaseDto;
import org.wisdom.exception.BusinessException;
import org.wisdom.vo.PageModel;
import org.wisdom.vo.ResponseResult;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 资源API
 *
 * @author 张智研
 * @date 2022/05/27 21:05
 **/
@Slf4j
@RequiredArgsConstructor
@WisdomController
public class ResourceControllerImpl implements ResourceController {
    private final AppRepository appRepository;
    private final AppFacadeRepository appFacadeRepository;
    private final AppPageRepository appPageRepository;
    private final AppWidgetRepository appWidgetRepository;
    private final AppPageElementRepository appPageElementRepository;
    private final ResourceRepository resourceRepository;
    private final ResourceAssembler resourceAssembler;

    @Override
    public ResponseResult<String> saveApp(ResourceDto resourceDto) {
        AcApp app = this.resourceAssembler.resourceDtoToAppEntity(resourceDto);
        app = this.appRepository.save(app);
        return ResponseResult.ok(app.getId());
    }

    @Override
    public ResponseResult<String> saveAppFacade(ResourceDto resourceDto) {
        AcAppFacade appFacade = this.resourceAssembler.resourceDtoToAppFacadeEntity(resourceDto);
        appFacade = this.appFacadeRepository.save(appFacade);
        return ResponseResult.ok(appFacade.getId());
    }

    @Override
    public ResponseResult<String> saveAppPage(ResourceDto resourceDto) {
        AcAppPage appPage = this.resourceAssembler.resourceDtoToAppPageEntity(resourceDto);
        appPage = this.appPageRepository.save(appPage);
        return ResponseResult.ok(appPage.getId());
    }

    @Override
    public ResponseResult<String> saveAppPageElement(ResourceDto resourceDto) {
        AcAppPageElement appPageElement = this.resourceAssembler.resourceDtoToAppPageElementEntity(resourceDto);
        appPageElement = this.appPageElementRepository.save(appPageElement);
        return ResponseResult.ok(appPageElement.getId());
    }

    @Override
    public ResponseResult<String> saveAppPage(ResourcesDto resourcesDto) {
        List<AcAppPage> appPages = this.resourceAssembler.resourceDtoToAppPageEntity(resourcesDto.getResources());
        for(AcAppPage appPage : appPages) {
            appPage.setAppId(resourcesDto.getAppId());
        }
        this.appPageRepository.saveAll(appPages);
        return ResponseResult.ok();
    }

    @Override
    public ResponseResult<String> saveAppWidget(ResourceDto resourceDto) {
        AcAppWidget appWidget = this.resourceAssembler.resourceDtoToAppWidgetEntity(resourceDto);
        appWidget = this.appWidgetRepository.save(appWidget);
        return ResponseResult.ok(appWidget.getId());
    }

    @Override
    public ResponseResult<String> saveAppWidget(ResourcesDto resourcesDto) {
        List<AcAppWidget> appWidgets = this.resourceAssembler.resourceDtoToAppWidgetEntity(resourcesDto.getResources());
        for(AcAppWidget appWidget : appWidgets) {
            appWidget.setAppId(resourcesDto.getAppId());
        }
        this.appWidgetRepository.saveAll(appWidgets);
        return ResponseResult.ok();
    }



    @Override
    public ResponseResult<List<ResourceDto>> queryAllUserResourceList(String userId) {
        List<AcResource> resourceList = this.resourceRepository.findAllByUserId(userId);
        List<ResourceDto> resourceDtoList = this.resourceAssembler.resourceEntityToDto(resourceList);
        return ResponseResult.ok(resourceDtoList);
    }

    @Override
    public ResponseResult<List<ResourceDto>> queryAllUserResourceList() {
        String userId = WisdomContextHolder.getContext().getUserId();
        List<AcResource> resourceList = this.resourceRepository.findAllByUserId(userId);
        List<ResourceDto> resourceDtoList = this.resourceAssembler.resourceEntityToDto(resourceList);
        return ResponseResult.ok(resourceDtoList);
    }

    @Override
    @EnableDataFilter
    public ResponseResult<PageModel<ResourceDto>> queryAll(ResourceDto resourceDto) {
        AcResource resource;
        if(resourceDto.getResourceType() != null) {
            switch (resourceDto.getResourceType()) {
                case 1:
                    resource = this.resourceAssembler.resourceDtoToAppEntity(resourceDto);
                    break;
                case 2:
                    resource = this.resourceAssembler.resourceDtoToAppPageEntity(resourceDto);
                    break;
                case 3:
                    resource = this.resourceAssembler.resourceDtoToAppWidgetEntity(resourceDto);
                    break;
                case 4:
                    resource = this.resourceAssembler.resourceDtoToAppPageElementEntity(resourceDto);
                    break;
                case 5:
                    resource = this.resourceAssembler.resourceDtoToAppFacadeEntity(resourceDto);
                    break;
                default:
                    resource = this.resourceAssembler.resourceDtoToResourceEntity(resourceDto);
                    break;
            }
        }else {
            resource = this.resourceAssembler.resourceDtoToResourceEntity(resourceDto);
        }
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("appId", ExampleMatcher.GenericPropertyMatcher::contains)
                .withMatcher("pageId", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("title", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("permission", ExampleMatcher.GenericPropertyMatchers.contains());
        Example<AcResource> resourceExample = Example.of(resource, matcher);
        PageModel<ResourceDto> pageModel = new PageModel<>();
        List<ResourceDto> resourceDtoList;
        if(resourceDto.getIsPage()) {
            Page<AcResource> resourcePage = this.resourceRepository.findAll(resourceExample, PageRequest.of(resourceDto.getPageNumber() - 1, resourceDto.getPageSize(), Sort.unsorted()));
            resourceDtoList = this.resourceAssembler.resourceEntityToDto(resourcePage.getContent());
            pageModel.setPageSize(resourcePage.getSize());
            pageModel.setPageNumber(resourcePage.getNumber() + 1);
            pageModel.setTotalPages(resourcePage.getTotalPages());
            pageModel.setTotalElements(resourcePage.getTotalElements());
        }else {
            List<AcResource> resourceList = this.resourceRepository.findAll(resourceExample);
            resourceDtoList = this.resourceAssembler.resourceEntityToDto(resourceList);
            resourceDtoList.sort(Comparator.comparing(BaseDto::getCreateTime));
            pageModel.setPageNumber(1);
            pageModel.setPageSize(resourceDtoList.size());
            pageModel.setTotalPages(1);
            pageModel.setTotalElements(resourceDtoList.size());
        }
        pageModel.setContent(resourceDtoList);
        return ResponseResult.ok(pageModel);
    }

    @Override
    public ResponseResult<ResourceDto> get(String resourceId) {
        AcResource resource = this.resourceRepository.findById(resourceId).orElse(null);
        if (resource == null) {
            throw new BusinessException("资源" + resourceId + "不存在！");
        }
        ResourceDto resourceDto = this.resourceAssembler.resourceEntityToDto(resource);
        return ResponseResult.ok(resourceDto);
    }

    @Override
    public ResponseResult<String> delete(String resourceIds) {
        List<String> ids = Arrays.stream(resourceIds.split(",")).collect(Collectors.toList());
        for(String id : ids) {
            Optional<AcResource> optionalAcResource = this.resourceRepository.findById(id);
            optionalAcResource.ifPresent(this.resourceRepository::delete);
        }
        return ResponseResult.ok();
    }
}
